package xyz.hubery.aspect;


import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.sun.tracing.dtrace.ArgsAttributes;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import xyz.hubery.domain.SysUserLog;
import xyz.hubery.service.SysUserLogService;
import xyz.hubery.service.SysUserRoleService;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * web 管理员 日志切面
 */
@Aspect
//@Component
@Order(2)
@Slf4j
public class WebLogAdminAspect {
    @Autowired
    private SysUserLogService userLogService;


    /**
     * 定义切点
     */
    @Pointcut("execution(* xyz.hubery.controller.*.*(..))")
    public void webLog() {}

    /**
     * 环绕通知
     */
    @Around(value = "webLog()")
    public Object recordWebLog(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        StopWatch stopWatch = new StopWatch(); // 创建计时器
        stopWatch.start(); // 开始计时
        result = joinPoint.proceed(joinPoint.getArgs());
        stopWatch.stop(); // 结束计时


        // 获取认证对象
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        // 获取请求的上下文
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取URL地址
        String url = request.getRequestURL().toString();
        // 获取方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取目标对象的类型名称
        String targetClassName = joinPoint.getTarget().getClass().getName();
        // 获取方法上的@ApiOperation注解
        ApiOperation annotation = method.getAnnotation(ApiOperation.class);
        // 封装日志对象
        WebLog webLog = WebLog.builder()
                .basePath(StrUtil.removeSuffix(url, URLUtil.url(url).getPath()))
                .description(annotation == null ? " no desc " : annotation.value())
                .ip(request.getRemoteAddr())
                .parameter(getMethodParameter(method,joinPoint.getArgs()))
                .method(targetClassName + "." + method.getName())
                .result(result)
                .spendTime((int) stopWatch.getTotalTimeMillis()/1000)
                .uri(request.getRequestURI())
                .url(url)
                .username(authentication == null ? "anonymous" :authentication.getPrincipal().toString() )
                .build();

        // 封装日志对象
        SysUserLog userLog = new SysUserLog();
        userLog.setCreated(new Date());
        userLog.setDescription(webLog.getDescription());
        userLog.setMethod(webLog.getMethod());
        userLog.setUserId(webLog.getUsername().equals("anonymous") ? 0L : Long.parseLong(webLog.getUsername()));
        // 保存
        userLog.setId(Long.valueOf(IdWorker.getIdStr()));
        userLogService.save(userLog);
        return result;
    }

    /**
     * 获取方法参数列表
     * @return
     */
    private Map<String,Object> getMethodParameter(Method method,Object[] args) {
        // 获取方法参数名列表
        LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(method);
        Map<String,Object> methodParams = new HashMap<>();
        if(args != null && parameterNames != null) {
            for(int i=0;i< args.length;i++) {
                methodParams.put(parameterNames[i],args[i] == null ? "":JSON.toJSONString(args[i]));
            }
        }

        return methodParams;
    }
}
